package com.zxjbyte.yiyi.framework.operatelog.publisher;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.zxjbyte.yiyi.framework.common.util.EventBusUtil;
import com.zxjbyte.yiyi.framework.common.util.JsonUtil;
import com.zxjbyte.yiyi.framework.common.util.ServletXUtil;
import com.zxjbyte.yiyi.framework.common.util.AuthUtil;
import com.zxjbyte.yiyi.framework.operatelog.annotation.OperateLog;
import com.zxjbyte.yiyi.framework.operatelog.enums.OperateTypeEnum;
import com.zxjbyte.yiyi.framework.operatelog.event.OperateLogAddEvent;
import com.zxjbyte.yiyi.module.system.domain.dto.OperateLogAddDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;

/**
 * 操作日志事件推送
 * @Author zhangxingjia
 * @Date 2023/3/17 13:33
 * @Version: 1.0
 */
public class OperateLogPublisher {

    /**
     * 推送操作日志
     */
    public static void publishEvent(ProceedingJoinPoint joinPoint, Object result, OperateLog operateLog, Date proTime, int duration){
        // 构建请求日志
        OperateLogAddDTO addDto = new OperateLogAddDTO();
        addDto.setUserId(AuthUtil.getUserId());
        addDto.setTenantId(AuthUtil.getTenantId());
        addDto.setApplicationName(SpringUtil.getApplicationName());
        Class<?> clazz = joinPoint.getTarget().getClass();
        // 获取目标方法的Method对象
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        addDto.setClassName(clazz.getName());
        addDto.setMethodName(signature.getName());
        String name = operateLog.name();
        // 如果操作名为空, 则取@Operation中的
        if(StrUtil.isBlank(name)){
            Method method = ClassUtil.getDeclaredMethod(clazz, signature.getName(), signature.getParameterTypes());
            Operation annotation = method.getAnnotation(Operation.class);
            name = Optional.ofNullable(annotation).map(Operation::summary).orElse(null);
        }
        addDto.setName(name);
        // 如果操作模块为空, 则取Tag中的
        String module = operateLog.module();
        if(StrUtil.isBlank(module)){
            Tag tag = clazz.getAnnotation(Tag.class);
            module = Optional.ofNullable(tag).map(Tag::name).orElse(null);
        }
        addDto.setModule(module);
        addDto.setType(Optional.ofNullable(operateLog.type()[0]).map(OperateTypeEnum::getType).orElse(null));
        addDto.setDuration(duration);
        if(operateLog.logResultData()){
            addDto.setResultData(JsonUtil.toJsonAsString(result));
        }
        addDto.setStartTime(proTime);
        addDto.setCreateUser(AuthUtil.getUserName());
        addDto.setCreateTime(new Date());
        HttpServletRequest request = ServletXUtil.getRequest();
        if(Objects.nonNull(request)){
            addDto.setRequestUri(request.getRequestURI());
            addDto.setRequestMethod(request.getMethod());
            addDto.setUserAgent(ServletXUtil.getUserAgent(request));
            addDto.setUserIp(ServletXUtil.getClientIP(request));
            if(operateLog.logArgs()){
                addDto.setParams(ServletXUtil.getRequestContent(request));
            }
        }
        // 发布事件
        EventBusUtil.asyncPublishEvent(new OperateLogAddEvent(addDto));
    }
}
